package com.hotec.PROJECT_NAME.modules.sys.service;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.gemcap.framework.data.entity.BaseEntity;
import com.gemcap.framework.data.utils.UtilsDataReflection;
import com.google.common.collect.Sets;
import com.hotec.PROJECT_NAME.component.basic.BaseService;
import com.hotec.PROJECT_NAME.component.basic.ConstantKey;
import com.hotec.PROJECT_NAME.component.enums.SmsEnum;
import com.hotec.PROJECT_NAME.component.exception.exc.BizException;
import com.hotec.PROJECT_NAME.modules.sys.entity.SysAccount;
import com.hotec.PROJECT_NAME.modules.sys.entity.SysRole;
import com.hotec.PROJECT_NAME.modules.sys.entity.SysRoleAccount;
import com.hotec.PROJECT_NAME.modules.sys.mapper.SysAccountMapper;
import com.hotec.PROJECT_NAME.utils.UtilsSms;
import com.hotec.PROJECT_NAME.utils.UtilsSpring;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author llb
 * @date
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class SysAccountService extends BaseService<SysAccount, SysAccountMapper> {

    @Autowired
    SysRoleService sysRoleService;
    @Autowired
    SysRoleAccountService sysRoleAccountService;
    @Autowired
    SysMessageReadService sysMessageAccountService;

    @Override
    public SysAccount get(String id) {
        SysAccount sysAccount = super.get(id);
        if (sysAccount != null) {
            List<SysRoleAccount> sysRoleAccounts = sysRoleAccountService.queryAll(new SysRoleAccount().setAccountId(sysAccount.getId()));

            sysAccount.setRoleList(sysRoleAccounts.stream().map(item -> ((SysRole) new SysRole().setId(item.getRoleId()))).collect(Collectors.toList()));

        }
        return sysAccount;
    }


    /**
     * 保存后台用户并且授权角色
     *
     * @param entity
     */
    public void saveAndAccredit(SysAccount entity) {
        if(StrUtil.isBlank(entity.getUsername())){
            entity.setUsername(entity.getMobile());
        }

        if (StrUtil.isBlank(entity.getPassword())) {
            entity.setPassword("123qwe!@#");
        }

        if(StrUtil.isBlank(entity.getId())){
            Assert.isNull(
                    this.getOne(new SysAccount().setUsername(entity.getUsername())),
                    "登录名已存在"
            );


            Assert.isNull(
                    this.getOne(new SysAccount().setMobile(entity.getMobile())),
                    "手机号已存在"
            );

            entity.setPassword(bCryptPasswordEncoder.encode(entity.getPassword()));
        }

        entity.setCreateTime(new Date());

        this.save(entity);

        saveRoleList(entity);
    }

    public void saveRoleList(SysAccount entity) {
        List<SysRole> sysRoleList = entity.getRoleList();
        SysRoleAccount userRole = new SysRoleAccount();
        userRole.setAccountId(entity.getId());
        List<SysRoleAccount> list = sysRoleAccountService.query(ConstantKey.DEFAULT_ORDER_BY, userRole);
        if (CollectionUtils.isNotEmpty(list)) {
            sysRoleAccountService.dropById(list.stream().map(BaseEntity::getId).collect(Collectors.joining(",")));
        }
        try {
            SysRoleAccountService bean = UtilsSpring.getBean(SysRoleAccountService.class);

            for (SysRole item : sysRoleList) {
                bean.save(new SysRoleAccount().setAccountId(entity.getId()).setRoleId(item.getId()));
            }
        } catch (Exception e) {
            throw new BizException("抱歉，父角色，子角色必须分开添加,父角色包含子角色");
        }
    }


    public void saveAndAccreditAndBindCommunity(SysAccount entity) {
        this.saveAndAccredit(entity);
    }

    /**
     * 重置密码！
     */
    public void resetPwd(String username, String password) {

        SysAccount account = this.getOne(new SysAccount().setUsername(username));
        if (account == null) {
            throw new BizException("用户不存在！");
        }

        account.setPassword(bCryptPasswordEncoder.encode(password));
        super.preUpdate(account);
        this.mapper.updateByPrimaryKeySelective(account);
    }

    public SysAccount getWithRole(String id) {
        HashSet<String> props = Sets.newHashSet("sysOrg.id", "sysOrg.name");
        props.addAll(UtilsDataReflection.getAllFieldsName(SysAccount.class));
        SysAccount sysAccount = mapper.getProps(id, props);
        SysRoleAccount userRole = new SysRoleAccount();
        userRole.setAccountId(sysAccount.getId());
        List<SysRoleAccount> select = sysRoleAccountService.query(ConstantKey.DEFAULT_ORDER_BY, userRole);
        if (CollectionUtils.isNotEmpty(select)) {
            List<String> roleIds = select.stream().map(SysRoleAccount::getRoleId).collect(Collectors.toList());

            Example example = new Example(SysRole.class);
            example.createCriteria().andEqualTo("delFlag", "0").andIn("id", roleIds);
            sysAccount.setRoleList(sysRoleService.queryByExample(1, 1000, ConstantKey.DEFAULT_ORDER_BY, example).getList());
        }

        return sysAccount;
    }


    public SysAccount info(String currentAccountId) {
        SysAccount account = this.get(currentAccountId);

        Assert.notNull(account, "用户信息不存在");

        Assert.isTrue(!"1".equalsIgnoreCase(account.getDelFlag()), "账号无权限");

        account.setRoleList(sysRoleService.queryByAccountId(currentAccountId));

        return account;
    }

    @Override
    public void deleteById(List<SysAccount> list) {
        super.deleteById(list);
    }

    public void forgetPassword(SysAccount sysAccount) {

        Assert.notBlank(sysAccount.getUsername(), "请输入用户名");

        Assert.notBlank(sysAccount.getPassword(), "请传入要修改的密码");

        if (StringUtils.isBlank(sysAccount.getCode()) || !UtilsSms.valid(sysAccount.getUsername(), sysAccount.getCode(), SmsEnum.RESETPWD)) {
            throw new BizException("验证码错误！");
        }

        SysAccount account = this.getOne(new SysAccount().setUsername(sysAccount.getUsername()));

        Assert.notNull(account, "密码修改失败，不存在此用户名！");

        account.setPassword(bCryptPasswordEncoder.encode(sysAccount.getPassword()));

        this.preUpdate(account);

        this.mapper.updateByPrimaryKeySelective(account);
    }

    public void modifyPassword(SysAccount sysAccount) {
        Assert.isTrue(StrUtil.isNotBlank(sysAccount.getId()), "请传入要修改密码的用户ID标识");

        Assert.isTrue(StrUtil.isNotBlank(sysAccount.getPassword()), "请传入要修改的密码");

        SysAccount account = this.mapper.selectByPrimaryKey(sysAccount.getId());

        Assert.notNull(account, "未获取到需要修改密码的用户信息");

        //可选参数，如果传过来旧密码，则需要校验旧密码是否正确，校验通过才可继续操作
        if (StrUtil.isNotBlank(sysAccount.getOldPassword())) {
            Assert.isTrue(bCryptPasswordEncoder.matches(sysAccount.getOldPassword(), account.getPassword()), "旧密码不正确");
        }

        account.setPassword(bCryptPasswordEncoder.encode(sysAccount.getPassword()));

        this.preUpdate(account);

        this.mapper.updateByPrimaryKeySelective(account);
    }

    public SysAccount saveUser(SysAccount entity) {
        if (StrUtil.isBlank(entity.getId())) {
            if (StrUtil.isBlank(entity.getPassword())) {
                entity.setPassword("123qwe!@#");
            }
            if (StrUtil.isNotBlank(entity.getUsername())) {
                SysAccount exist = this.getOne(new SysAccount().setUsername(entity.getUsername()));
                if (Objects.nonNull(exist)) {
                    throw new BizException("要添加的账号已存在!");
                }
            }

            if (StrUtil.isNotBlank(entity.getMobile())) {
                SysAccount mobile = this.getOne(new SysAccount().setMobile(entity.getMobile()));
                if (Objects.nonNull(mobile)) {
                    throw new BizException("要添加的手机号已存在!");
                }
            }
            entity.setPassword(bCryptPasswordEncoder.encode(entity.getPassword()));
        }
        entity.setCreateTime(new Date());
        entity.setUsername(entity.getMobile());
        return this.save(entity);
    }
}
